home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / tnos / tnos100s / buckbook.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-21  |  23.7 KB  |  884 lines

  1. #ifdef CALLCLI
  2. /*
  3.    Fred Peachman KB7YW
  4.    7186 Northview Drive
  5.    Brookfield, OH 44403
  6.    Sun  03-01-1992
  7.  
  8.    This is a substitute for N4PCR's callsign server. The intent is to replace
  9.    N4PCR's callbook.c with this file - and have a callsign server that will
  10.    run off Buckmaster's CD-ROM: the October 1991 "HAM CALL" CD.
  11.  
  12.    The CD-ROM must be configured with a driver installed in config.sys,
  13.    and the mscdex.exe TSR must be running.
  14.  
  15.    The callserver database commands will configure the cd-rom.
  16.  
  17.    config.h must #define CALLCLI or CALLSERVER. If CALLSERVER is #define'd
  18.    CALLCLI is forced on by config.h. Only CALLCLI can be #define'd separately
  19.    of CALLSERVER so it is the default condition for compilation of this
  20.    module - which won't used at all if neither CALLCLI nor CALLSERVER are
  21.    #define'd in config.h.
  22.  */
  23.  
  24. #include <stdio.h>
  25. #include <string.h>
  26. #include <time.h>
  27. #include <sys/timeb.h>
  28. #include "global.h"
  29. #include "files.h"
  30. #include <stdlib.h>
  31. #include  <dos.h>
  32. #include <alloc.h>
  33. #include <ctype.h>
  34. #include <fcntl.h>
  35. #include <io.h>
  36.  
  37. #include "cmdparse.h"
  38. #include "config.h"
  39.  
  40. #ifdef CALLSERVER
  41. /* CD-ROM code by Fred Peachman KB7YW */
  42. char *CDROM = NULLCHAR;
  43. #endif
  44.  
  45. char  *Callserver = NULLCHAR;
  46.  
  47. /*struct database_activity
  48.   One of these structs gets filled out by init -
  49.   initializes data base for calls from hamcall.c -
  50.   should be able to handle generic functions across different data base
  51.   formats.
  52.  */
  53.   struct database_activity {
  54.     int type;                     /* for checking data/function formats*/
  55. #define USA 0
  56. #define CANADA 1
  57.     int  handle;                  /* -1 if unitialized  */
  58.     unsigned long record;         /* current record #                 */
  59.     void *record_buf;           /* where to read the record to      */
  60.   };
  61.  
  62.   struct months {
  63.     char *m;  /* name of month  */
  64.     int  d;   /* days in month  */
  65.   };
  66. /* The Buckmaster HAM CALL CD format for U.S. Callsign database       */
  67.   struct usa  {
  68.     char callsign[6];   /* None of these fields are ASCIIZ so be careful */
  69.     char lastname[24];
  70.     char firstname[11];
  71.     char middle[1];
  72.     char street[35];
  73.     char city[20];
  74.     char state[2];
  75.     char zip[5];
  76.     char fluff[8];      /* supreme nothingness                            */
  77.     char exp[2];        /* 'X3' if license expired                        */
  78.     char born[2];       /* Last two digits of year of birth  i.e. '54     */
  79.     char expiryr[2];    /* Last two digits of year of license expiration  */
  80.     char expirday[3];   /* The day of the year that license expires       */
  81.     char validyr[2];    /* year that license was issued                   */
  82.     char validday[3];   /* day of the year that license was issued        */
  83.     char class[1];      /* 1 letter license classification                */
  84.     char endline[2];    /* file marker                                    */
  85.   };
  86.  
  87. /* The Buckmaster HAM CALL CD format for Canadian Callsign database
  88.    It is 0x9a bytes long (154) The first record has a blank callsign field
  89.    that should be no problem!                                             */
  90.  
  91.   struct canada  {
  92.     char callsign[8];
  93.     char name[0xe8 - 0xa2];
  94.     char street[0x10a - 0xe8];
  95.     char town[0x121-0x10a];
  96.     char province[0x12c-0x121];
  97.     char zip[6];
  98.     char endline[2];
  99.   };
  100.                     /* generic function calls: headers */
  101. static int
  102. init __ARGS((struct database_activity *db,int type,int s));
  103. static int
  104. close_down __ARGS((struct database_activity *db));
  105. static void
  106. disp __ARGS((char *cfield, int siz, int s));
  107. static int
  108. readrec __ARGS((struct database_activity *db));
  109. static int
  110. displayrec __ARGS((struct database_activity *db, int s));
  111. static int
  112. find_call __ARGS((struct database_activity *db, char *callsign));
  113. static int
  114. make_mask __ARGS((char *mask, char *callsign, int s));
  115.  
  116. static int
  117. docallserver_hostname __ARGS((int argc,char *argv[],void *p));
  118. static int
  119. docallserver_databases __ARGS((int argc,char *argv[],void *p));
  120.  
  121.                         /* for u.s.a database:  */
  122. static int
  123. display_usa __ARGS((void *,int s));
  124. static int
  125. comp_usa_calls __ARGS((char *, char *));
  126.  
  127.                         /* for canada database  */
  128. static int
  129. display_canada __ARGS((void *,int s));
  130. static int
  131. comp_canada_calls __ARGS((char *, char *));
  132.  
  133. /* most of this module is server code, but some is client: CALLCLI is by
  134.    default - forced on in config.h whenever CALLSERVER is #define'd */
  135. #ifdef CALLSERVER
  136.  
  137. /* How many different databases are we supporting right now?              */
  138. #define DATABASE_TYPES 2
  139.  
  140. /* how many passes should we make before we give up (in find_call)?    */
  141. #define MAXREADS 30
  142. /*----------------------------------------------------------------------------
  143.     Here are arrays of variables to use depending on which database is
  144.     needed. In each array make sure the value order is same as defs for
  145.     database_activity.types i.e. USA, CANADA, ....
  146.  
  147.     In order to tack on another database, add an element for each of these
  148.     arrays, increment the definition for DATABASE_TYPES (above), and
  149.     tell your program how to tell init to use the new one.  In this
  150.     module the launcher (cb_lookup) will figure out which database to
  151.     initialize ("init(type, callsign,s)").
  152.  
  153.     Basically for the new database you would only need to specify its file
  154.     name in database[], write a display function and specify it in
  155.     displayfunc[], specify the size of one record in record_size[],
  156.     write a callsign comparison function and specify it in compare_calls[],
  157.     and specify the byte offset of the callsign field within a record -
  158.     specify this offset in call_offset[] - it will probably be 0 anyway.
  159.  
  160.     You need to write something in cb_lookup to tell init when to initialize
  161.     your new database. Basically if "call" satisfies inspection, initialize
  162.     the appropriate database.
  163.  */
  164.  
  165. char *database[DATABASE_TYPES]  = {
  166.   { NULLCHAR  }, /* "S:\\HAM0\\HAMCALL.129"},  USA  */
  167.   { NULLCHAR  }  /* "S:\\HAM0\\CANADA2.DAT"}   CANADA */
  168. };
  169.  
  170. char *database_label[DATABASE_TYPES]  = {
  171.   { "usa"},{"canadian"}
  172. };
  173.  
  174. int (*displayfunc[DATABASE_TYPES])(void *, int) = {
  175.   { display_usa },
  176.   { display_canada }
  177. };
  178.  
  179. /* basic record size, in bytes, in each database  */
  180. int record_size[DATABASE_TYPES] =   {   129, 154  };
  181.  
  182.             /* How fresh is this stuff in the database?  */
  183. static char *Volume = "October 1991";
  184.  
  185.             /* number of records in each type of database */
  186. unsigned long records[DATABASE_TYPES];
  187.  
  188.        /* The database-specific callsign comparison procedure  */
  189. int (*compare_calls[DATABASE_TYPES]) __ARGS((char *,char *)) = {
  190.   {comp_usa_calls},{comp_canada_calls}
  191. };
  192. /*      At what offset within a database struct is the callsign located?
  193.                Look at struct usa and struct canada above
  194.  */
  195. int call_offset[DATABASE_TYPES] = { 0,0 };
  196.  
  197. char *BusyServer = "\n\nThe callsign server is busy right now\n\
  198. .... please call back later\n\n";
  199.  
  200. static char *TAB = "        ";
  201.  
  202.                    /* for use in display_usa */
  203. struct months month[12] = {
  204.   {"January", 31},{"February",28},{"March",31},{"April",30},{"May",31},
  205.   {"June",30},{"July",31},{"August",31},{"September",30},{"October",31},
  206.   {"November",30},{"December",31}
  207.   };
  208. /*----------------------------------------------------------------------------
  209. /* --------------- Generic (database-independent) functions ----------------*/
  210. /*----------------------------------------------------------------------------
  211.   Initialize a database activity struct. this consists of making sure
  212.   the database file is opened and that the number of records in that
  213.   file is computed. Also a record_buf is malloced for each db.
  214.  */
  215. static int
  216. init(db, type, s)
  217. struct database_activity *db;
  218. int type;
  219. int s;
  220. {
  221. long tmp;
  222. int i;
  223. extern char *Callserver;  /* declared in calldbd.c  */
  224.   if ((type < 0) || (type >= DATABASE_TYPES))  return -1;
  225.  
  226.   db->type = type;
  227.  
  228.   i = db->handle = _open(database[type], O_RDONLY | O_BINARY);
  229.   if (i == -1) {
  230.     usprintf(s,"%s",BusyServer);
  231.     return 0;
  232.   }
  233.   for (i = 0; i < 50; i++)  pwait(NULL);
  234.   /* The CD-ROM is a slow device!! - give other processes lots of slack */
  235.  
  236.   tmp = filelength(db->handle);
  237. /*   if (tmp == -1L)  {
  238.     usprintf(s,"Error reading length of file \"%s\"\n\
  239.     please report to the sysop at %s\n",database[type], Callserver);
  240.     return -1;
  241.   }
  242. */
  243.   records[type] = tmp/((long) record_size[type]);
  244.  
  245.   db->record_buf = (char *)malloc(record_size[type]);
  246.   if (db->record_buf == NULL) {
  247.     usprintf(s,"%s",BusyServer);  /* No memory to allocate, actually  */
  248.     return -1;
  249.   }
  250.   return 0;
  251. }
  252.  
  253. static int
  254. close_down(db)
  255. struct database_activity* db;
  256. {
  257.   free(db->record_buf);
  258.   _close(db->handle);
  259. }
  260. static int
  261. invalid_callsign(callsign, s)
  262. char *callsign;
  263. int s;
  264. {
  265.   usprintf(s,"\n\n\"%s\" is an invalid callsign\n\n", callsign);
  266.   return -1;
  267. }
  268.  
  269. /* make_mask makes a Buckmaster-compatible mask out of the callsign.
  270.   caller must allocate 6 bytes exactly for "mask" or 7 to make an ascii
  271.   string out of it.
  272.  
  273.   callsign is the callsign we are looking to match; mask is the same
  274.   callsign only padded to Left with a space if necessary to keep the
  275.   callsign digit at position 2 (starting with 0), and padded with spaces
  276.   to the right if necessary to make sure the mask is exactly 6 digits
  277.   long.
  278.  
  279.   This routine will work right for US or Canadian callsigns, but NOT with
  280.   foreign callsigns (that contain more than one numeric character) it
  281.   will fail!
  282.  */
  283.  
  284. static int
  285. make_mask(mask, callsign,s)
  286. char *mask;
  287. char *callsign;
  288. int s;
  289. {
  290. int j, k, len, already=0;
  291. char *q, *p;
  292. char tmp[7];
  293.  
  294.   len = strlen(callsign);
  295.  
  296.   /* there must be only ONE digit-character at position 1 or 2
  297.       (starting from 0)  */
  298.   q = callsign;
  299.   already = 0;
  300.   for (j = 0; j < len; j++)   {
  301.     if (isdigit(*q++))  {
  302.       if (!(already++)) k = j;/* already counts the number of digit chars */
  303.       else return invalid_callsign(callsign,s);
  304.     }
  305.   }
  306.   if ((k < 1) || ( k > 2))  return invalid_callsign(callsign,s);
  307.  
  308. /* FINALLY, Buckmaster pads to the left with spaces to position the digit at
  309.   mask[2] */
  310.  
  311.   q = mask;
  312.   for (j = 0; j < 6; j++) *q++ = ' '; /* initialize!  */
  313.  
  314.   p = callsign;
  315.   q = mask;
  316.  
  317.   switch (k)  {
  318.     case 1:
  319.     *q++ = ' '; /* left-pad with a space  */
  320.     break;
  321.  
  322.     case 2:
  323.     break;
  324.  
  325.     default:
  326.     break;
  327. /*  usprintf(s,"Error in make_mask %s line %d\n",__FILE__,__LINE__);
  328.     exit(255);
  329. */
  330.   }
  331.  
  332.   for (j = 0; j < len; j++) *q++ = *p++;
  333.  
  334.   return ((int) (mask[2]) &0x0f); /* returns digit of the valid U.S. callsign */
  335. }
  336.  
  337. /* a method for display of non-ASCIIZ strings */
  338. static void
  339. disp(cfield,siz,s)
  340. char *cfield;
  341. int siz;
  342. int s;
  343. {
  344. char *q;
  345. int i, sw=0;
  346.  
  347.   q = cfield;
  348.   for (i = 0; i < siz; i++) {
  349.     if ((!sw) || (*q != ' ')) usputc(s, (int) *q, stdout);
  350.     if (*q == ' ') sw = 1;
  351.     else sw = 0;  /* We will print out one space before we quit!  */
  352.     q++;
  353.   }
  354. }
  355. static int
  356. readrec(db)
  357. struct database_activity *db;
  358. {
  359. unsigned long tmp, filepointer;
  360. size_t n;
  361. int st;
  362.  
  363.   st = db->type;
  364.   filepointer = db->record*((long) record_size[st]);
  365.   tmp = lseek(db->handle, filepointer,SEEK_SET);
  366. /*
  367.   if (tmp != filepointer) {
  368.     usprintf(s,"filepointer moved to %08lu\n", tmp);
  369.     return -1;
  370.   }
  371. */
  372.   n = _read(db->handle, db->record_buf,record_size[st]);
  373. /*
  374.   if (n != record_size[st]) {
  375.      usprintf(s,"Error reading database\n");
  376.      return -1;
  377.   }
  378.   else
  379. */
  380.     return 0;
  381. }
  382.  
  383. static int
  384. displayrec(db,s)
  385. struct database_activity *db;
  386. int s;
  387. {
  388. int (*func)(void *v, int s);
  389.  
  390.   func = displayfunc[db->type];
  391.   usprintf(s,"\n%s*** Record # % 8lu:***\n",TAB, db->record);
  392.   func(db->record_buf,s);
  393.   return 0;
  394. }
  395. /* find_call: Find the record number that matches the callsign. For any
  396.    callbook data where the records are all of the same length. The
  397.    returned record value is found as db->record.
  398.  
  399.    If the input callsign needs to be converted to a search mask in any
  400.    way, do it then call findcall.
  401.  
  402.    The returned int value is the number of records read during the search
  403.    process.
  404.  */
  405.  
  406. static int
  407. find_call(db, callsign)
  408. struct database_activity *db;
  409. char *callsign;
  410. {
  411. int i, ret, met= 0, reads = 0;
  412. long ra,rz;  /* first, middle, last record numbers */
  413. int (*comp)(char *, char *);
  414. int st;
  415. char *rec_call;
  416.  
  417.   st = db->type;  /* determine database structure type  */
  418.   comp = compare_calls[st];
  419. /* set initial pointers */
  420.   ra = 0L;
  421.   rz = records[st] - 1L;
  422.   db->record = (ra + rz)/2L;  /* go for the middle  */
  423.  
  424.   rec_call = (char *)db->record_buf + call_offset[st];
  425.   ret = 1;
  426.   while (ret != 0)  {
  427.     readrec(db);  /* read in the data pointed to by db->record  */
  428.     for (i=0; i < 50; i++)
  429.       pwait(NULL);  /* sit back and let other processes run for a while.
  430.       The CD-ROM is a slow-access device so lots of other processes may
  431.       be waiting or trying to run - like the keyboard!!! */
  432.  
  433.     reads++;
  434.     ret = comp(callsign, rec_call);
  435.  
  436.     if (ret < 0)  /* callsign < record's callsign field  */
  437.       rz = db->record - 1L;
  438.     else if (ret > 0)  /* callsign > record's callsign field  */
  439.       ra = db->record + 1L;
  440.     else return reads;
  441.  
  442.     if (reads == MAXREADS) return -1;  /* Abnormal return  */
  443.     else if (ra >= rz)  {
  444.       if (met)  return -1;
  445.       else  met = 1;  /* catch this if it happens a second time!  */
  446.     }
  447.     db->record = (ra + rz)/2L;
  448.   }
  449.   /* not reached  */
  450. }
  451. /*---------------- ROUTINES FOR U.S. CALLSIGN DATABASE ----------------------*/
  452.  
  453. /* getdaynum: given a character array 'p' of 'siz' elements, convert the
  454.    array to an ASCIIZ string, return the integer value that it
  455.    represents.
  456.  */
  457. static int
  458. getdaynum(p,siz)
  459. char *p;
  460. int siz;
  461. {
  462. char *q, tmp[80];
  463. int ret, i;
  464.  
  465.   q = p;
  466.   for (i = 0; i < siz; i++) {
  467.     tmp[i] = *q++;
  468.   }
  469.   tmp[i] = '\0';
  470.  
  471.   ret = atoi(tmp);
  472.  
  473.   return ret;
  474. }
  475. /* yrval:
  476.    Take the two-letter year code and determine if we have a year that is in
  477.    the 1900's or the 21st century. Return a proper integer answer:
  478.    i.e. "2002" or "1998".
  479.  */
  480. static int
  481. yrval(yrin)
  482. char *yrin;
  483. {
  484. int i, num;
  485.  
  486.     num = getdaynum(yrin, 2);
  487.  
  488.     if (num > 90) num += 1900;
  489.     else num += 2000;
  490.     return num; /* an integer */
  491. }
  492. /* day_calc: given the 3-element character array 'day' and the 2-element
  493.    character array 'yr', construct a string that returns the date for
  494.    that year, in the form "February 28, 2002" */
  495.  
  496. static char *
  497. day_calc(day, daystr, yr)
  498. char day[3];
  499. char *daystr;
  500. char yr[2];
  501. {
  502. int i, daynum, subt, year, t;
  503. char *q, tmp[4];
  504. int leap = 0;
  505.  
  506.     year = yrval(yr);
  507.  
  508.     if (!(year%4))  leap = 1; /* evenly divisible by four means leap year */
  509.  
  510.     daynum = getdaynum(day, 3);
  511.     if (daynum == 0)  return NULL;
  512.  
  513.  
  514.     subt = 0;
  515.     for (i = 0; i < 12; i++)  {
  516.       if (((t = subt + ((i == 1) ? leap : 0) + month[i].d)) > daynum) break;
  517.       else (subt = t);
  518.     }
  519.     t = daynum - subt;
  520.     if (i == 12)  daystr[0] = '\0';
  521.     else  sprintf(daystr,"%s %d, %d", (t > 0 ? month[i].m : month[--i].m),
  522.                   (t > 0 ? t : month[i].d + ((i==1) ? leap : 0)),
  523.                   year);
  524.     return daystr;
  525. }
  526. /* comp_usa_calls compares the sought-for callsign with a mask of the
  527.    type encountered in the callsign field of a struct usa,
  528.  
  529.   returns 0 if they match, -1 if mask1 < mask2, 1 if mask1 > mask2.
  530.   mask1 is the callsign requested, mask2 is the database callsign from
  531.   the record under test for match.
  532.  */
  533. static int
  534. comp_usa_calls(mask1, mask2)
  535. char mask1[6];
  536. char mask2[6];
  537. {
  538. int i;
  539. char *p, *q;
  540.  
  541.   /* This is in accordance with the way that Buckmaster orders callsigns
  542.      on its CD-ROM database, so follow along:
  543.    */
  544.  
  545.   p = &mask1[2], q = &mask2[2];
  546.   for (i =2; i < 6; i++)  {
  547.     if (*p != *q)  return (int) *p - (int) *q;
  548.     p++, q++;
  549.   }
  550.   p = mask1, q = mask2;
  551.   for (i =0; i < 2; i++)  {
  552.     if (*p != *q)  return (int) *p - (int) *q;
  553.     p++, q++;
  554.   }
  555.   return 0;
  556. }
  557.  
  558.  
  559. /*
  560.     Buckmaster CD-ROM October 1991
  561.       *** Record #   452100:***
  562. Call:   KB7YW
  563.         FREDERICK A PEACHMAN
  564.         7186 NORTHVIEW DR
  565.         BROOKFIELD , OH 44403
  566. Born:   1954
  567. Class:  EXTRA
  568. Exp:    March 29, 1998
  569.  */
  570. static int
  571. display_usa(us,s)
  572. void *us;
  573. int s;
  574. {
  575. struct usa *u;
  576. char daystr[20];
  577. int yeardate;
  578.  
  579.   u = (struct usa *)us;
  580.   usprintf(s, "CALL:   ");
  581.   disp(u->callsign,sizeof(u->callsign),s);
  582.   usprintf(s,"\n%s", TAB);
  583.   disp(u->firstname,sizeof(u->firstname),s);
  584.   disp(u->middle,sizeof(u->middle),s);
  585.   usprintf(s," ");
  586.   disp(u->lastname,sizeof(u->lastname),s);
  587.   usprintf(s,"\n%s", TAB);
  588.   disp(u->street,sizeof(u->street),s);
  589.   usprintf(s,"\n%s", TAB);
  590.   disp(u->city,sizeof(u->city),s);
  591.   usprintf(s,", ");
  592.   disp(u->state,sizeof(u->state),s);
  593.   usprintf(s," ");
  594.   disp(u->zip,sizeof(u->zip),s);
  595.   if (u->born[0] != '-')  {
  596.     usprintf(s,"\nBorn:   19");
  597.     disp(u->born,sizeof(u->born),s);
  598.   }
  599.   usprintf(s,"\nClass:  ");
  600.  
  601.   switch(u->class[0])   {
  602.     case 'N':
  603.     usprintf(s,"NOVICE");
  604.     break;
  605.  
  606.     case 'T':
  607.     usprintf(s,"TECHNICIAN");
  608.     break;
  609.  
  610.     case 'C':
  611.     usprintf(s, "CLUB STATION");
  612.     break;
  613.  
  614.     case 'G':
  615.     usprintf(s,"GENERAL");
  616.     break;
  617.  
  618.     case 'A':
  619.     usprintf(s,"ADVANCED");
  620.     break;
  621.  
  622.     case 'E':
  623.     usprintf(s,"EXTRA");
  624.     break;
  625.  
  626.     default:
  627.     usprintf(s,"%c", u->class[0]);
  628.   }
  629.   usprintf(s,"\n");
  630.  
  631.   yeardate = yrval(u->expiryr);
  632.   if (day_calc(u->expirday, daystr, u->expiryr) != NULL)  {
  633.     if (daystr[0] != '\0')  {
  634.       if ((u->exp[0] == ' ') || (yeardate > 2000))  {
  635.         usprintf(s,"Expires:");
  636.         usprintf(s,"%s\n", daystr);
  637.       }
  638.       else usprintf(s,"%sUnknown Expiration Date\n",TAB);
  639.     }
  640.     else usprintf(s,"%sUnknown Expiration Date\n",TAB);
  641.   }
  642.   return 0;
  643. }
  644.  
  645. /*---------- Procedures specific to Canadian Callsign DataBase----------------*/
  646. static int
  647. display_canada(us,s)
  648. void *us;
  649. int s;
  650. {
  651. struct canada *u;
  652. #define DISP(x) {usprintf(s,"\n        ");\
  653.                  disp(x, sizeof(x),s);}
  654.  
  655.   u = (struct canada *) us;
  656.  
  657.   DISP(u->callsign);
  658.   DISP(u->name);
  659.   DISP(u->street);
  660.   DISP(u->town);
  661.   disp(u->zip, sizeof(u->zip),s);
  662.   usprintf(s,"\n");
  663.   usprintf(s,"%sCANADA\n",TAB);
  664.  
  665.   return 0;
  666. }
  667. /* comp_canada_calls compares the sought-for callsign with a mask of the
  668.    type encountered in the callsign field of a struct canada,
  669.  
  670.   returns 0 if they match, -1 if mask1 < mask2, 1 if mask1 > mask2.
  671.   mask1 is the callsign requested, mask2 is the database callsign from
  672.   the record under test for match.
  673.  */
  674.  
  675. static int
  676. comp_canada_calls(mask1, mask2)
  677. char mask1[6];
  678. char mask2[6];
  679. {
  680. int i;
  681. char *p, *q;
  682.  
  683.   p = mask1, q = mask2;
  684.   for (i =0; i < 6; i++)  {
  685.     if (*p != *q)  return (int) *p - (int) *q;
  686.     p++, q++;
  687.   }
  688.   return 0;
  689. }
  690. /* One of three public  functions!  */
  691. int
  692. cb_lookup(s,call)
  693. int s;
  694. char  *call;
  695. {
  696. /* This is the launcher.  Get rid of any callsign validity-checking code
  697.   that happens before calling cb_lookup. Eventually we will have to
  698.   launch the US, Canadian, or foreign Buckmaster CD databases. For right
  699.   now, tho, we only have USA and CANADA.
  700.  */
  701. char *q;
  702. int len, j;
  703. char mask[7];
  704. struct database_activity DA;
  705. char *cant = "Can't handle callsign \"%s\"\n";
  706.  
  707.                   /* FIRST TEST CALLSIGN FOR VALIDITY */
  708.  
  709.   /* Buckmaster only matches callsigns of 4 to 6 letters in length  */
  710.   len = strlen(call);
  711.   if ((len < 4) || (len > 6)) return invalid_callsign(call,s);
  712.  
  713.   for (j = 0; j < 6; j++) call[j] = toupper(call[j]);
  714.  
  715.                   /* every character must be alphanumeric */
  716.   q = call;
  717.   for (j = 0; j < len; j++) if (!(isalnum(*q++)))
  718.     return invalid_callsign(call,s);
  719.  
  720.   q = call;
  721.   switch (*q) {
  722.     case 'A':
  723.     case 'K':
  724.     case 'N':
  725.     case 'W':
  726.     if ((init(&DA, USA, s)) == -1)  return 0;
  727.     if ((make_mask(mask, call, s)) == -1) {
  728.       close_down(&DA);
  729.       return 0;
  730.     }
  731.     break;
  732.  
  733.     case 'V':
  734.       if ((strncmp(call,"VO",2) == 0) || (strncmp(call,"VE",2) == 0)) {
  735.         if ((init(&DA, CANADA, s)) == -1)  return 0;
  736.         if ((make_mask(mask, call, s)) == -1)   {
  737.           close_down(&DA);
  738.           return 0;
  739.         }
  740.       }
  741.       else  {
  742.         usprintf(s,cant,call);
  743.         return 0;
  744.       }
  745.       break;
  746.  
  747.     default:
  748.         usprintf(s,cant,call);
  749.       return 0;
  750.   }
  751.  
  752.   if ((find_call(&DA,mask)) == -1)
  753.     usprintf(s, "\n\nCallsign \"%s\" not found\n\n",call);
  754.   else {
  755.     displayrec(&DA,s);
  756.     usprintf(s,"\n%sDatabase date: %s\n\n\n",TAB, Volume);
  757.   }
  758.     /* find_call returns with appropriate record already read into
  759.        DA.record_buf and the return value is -1 for error or number of
  760.        seeks required on success.
  761.      */
  762.     
  763.   close_down(&DA);
  764.   return 0;
  765. }
  766. #endif /* #ifdef CALLSERVER */
  767.  
  768. struct cmds Callserver_cmds[] = {
  769.   "hostname", docallserver_hostname, 0,  0,  NULLCHAR,
  770. #ifdef CALLSERVER
  771.   "database", docallserver_databases,  0,  0,  NULLCHAR,
  772. #endif
  773.   NULLCHAR,
  774. };
  775.  
  776. /* Another public, headered in commands.h */
  777. int
  778. docallserver(argc,argv,p)
  779. int argc;
  780. char *argv[];
  781. void *p;
  782. {
  783.   return subcmd(Callserver_cmds, argc, argv, p);
  784. }
  785.  
  786. static int
  787. docallserver_hostname(argc,argv,p)
  788. int argc;
  789. char *argv[];
  790. void *p;
  791. {
  792.     if(argc < 2)    {
  793.         if(Callserver != NULLCHAR)
  794.             tprintf("The callserver's hostname is: %s\n",Callserver);
  795.         else    {
  796.             tprintf("Callserver not configured!\n");
  797.             tprintf("Usage: callserver hostname <hostname>|<ip_address>\n");
  798.         }
  799.     } else {
  800.         if(Callserver != NULLCHAR)
  801.             free(Callserver);
  802.         Callserver = strdup(argv[1]);
  803.     }
  804.     return 0;
  805. }
  806.  
  807. #ifdef CALLSERVER
  808. static int
  809. docallserver_databases(argc,argv,p)
  810. int argc;
  811. char *argv[];
  812. void *p;
  813. {
  814. int t;
  815.  
  816.   if (argc < 2) {
  817.     for (t = 0; t < DATABASE_TYPES; t++)  {
  818.       tprintf("callserver database %s ", database_label[t]);
  819.       if (database[t] == NULLCHAR)  {
  820.         tprintf("not configured.\n");
  821.       }
  822.       else  tprintf("%s\n", database[t]);
  823.     }
  824.     return 0;
  825.   } else  { /* argc >= 2 */
  826.       for (t = 0; t < DATABASE_TYPES; t++)  {
  827.         if (strncmp(database_label[t],argv[1],strlen(argv[1])) == 0)  {
  828.           if (argc < 3) {
  829.             tprintf("callserver database %s ", database_label[t]);
  830.             if (database[t] == NULLCHAR)  tprintf("not configured\n");
  831.             else  tprintf("%s\n", database[t]);
  832.           } else  { /* argc >= 3  */
  833.             if (database[t] == NULLCHAR)  free(database[t]);
  834.             database[t] = strdup(argv[2]);
  835.           }
  836.           return 0; /* we have found our match with database_label[t] */
  837.         }
  838.       }
  839.       /* no match with database_label: which database?  */
  840.       tprintf("Usage: callserver database ");
  841.       for (t = 0; t < DATABASE_TYPES; t++)  {
  842.         tprintf("%s", database_label[t]);
  843.         if ( t < DATABASE_TYPES - 1)  tprintf("|");
  844.       }
  845.       tprintf(" <database drive:/path/filename>\n");
  846.       return -1;
  847.   }
  848.   /* not reached  */
  849. }
  850.  
  851. /* the last public of this module, also headered in commands.h  */
  852. int
  853. docdrom(argc,argv,p)
  854. int argc;
  855. char *argv[];
  856. void *p;
  857. {
  858. extern char *CDROM; /* declared above, this module  */
  859.  
  860.   if (argc < 2) {
  861.     if (CDROM == NULLCHAR)  {
  862.       tprintf("CDROM drive letter not specified\n");
  863.     }
  864.     else  tprintf("CDROM drive is \"%s\"\n", CDROM);
  865.     return 0;
  866.   }
  867.   else  {
  868.     if ((argv[1][2] == '\0')    &&
  869.         (isalpha(argv[1][0]))   &&
  870.         (argv[1][1] == ':'))  {
  871.           if (CDROM != NULLCHAR)  free(CDROM);
  872.           CDROM = strdup(argv[1]);
  873.           return 0;
  874.     }
  875.     else  {
  876.       tprintf("Usage: \"cdrom driveletter:\", e.g. \"cdrom s:\"\n");
  877.       return 1;
  878.     }
  879.   }
  880.   /* not reached  */
  881. }
  882. #endif  /* #ifdef CALLSERVER  */
  883. #endif  /* #ifdef CALLCLI */
  884.